# This file is part of libvcc.py.

# libvcc.py is free software: you can redistribute it and/or modify it under the terms of the GNU General 
# Public License as published by the Free Software Foundation, either version 3 of the License, or (at 
# your option) any later version.

# libvcc.py is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the 
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 
# License for more details.

# You should have received a copy of the GNU General Public License along with libvcc.py. If not, see 
# <https://www.gnu.org/licenses/>. 

import asyncio
import logging
from typing import Any

from .constants import *
from .sock import Connection

class BasicBridge:
    """The middle-level api of vcc socket"""
    def __init__(self, data: Data, conn: Connection) -> None:
        self.data = data
        self.conn = conn

    async def init(self) -> None:
        await self.conn.init()

    async def send(
        self, *, 
        type: int = REQ.MSG_SEND, 
        uid: int = 0, 
        session: int | None = None, 
        flags: int = 0, 
        username: str | None = None, 
        msg: str | bytes = "",
    ) -> None:
        if username is None:
            username = self.data.username

        if session is None:
            session = self.data.sess

        await self.conn.send(
            magic = VCC_MAGIC, 
            type = type, 
            uid = uid, 
            session = session, 
            flags = flags, 
            username = username, 
            msg = msg
        )

    async def send_relay(
        self, *, 
        uid: int = 0, 
        session: int | None = None, 
        username: str | None = None, 
        msg: str = "\0", 
        visible: str = ""
    ) -> None:
        if session is None:
            session = self.data.sess
        if username is None:
            username = self.data.username
        await self.conn.send_relay(
            magic = VCC_MAGIC_RL,
            uid = uid,
            session = session,
            username = username,
            msg = msg,
            visible = visible
        )

    async def recv(self) -> tuple[RawRequest, Request] | tuple[RawRelay, Relay]:
        return await self.conn.recv()

class Bridge:
    """The high-level api of vcc socket"""
    def __init__(self, data: Data, conn: Connection) -> None:
        self.bridge = BasicBridge(data, conn)

    # properties
    @property
    def username(self) -> str:
        return self.bridge.data.username

    @username.setter
    def username(self, value: str) -> None:
        self.bridge.data.username = value

    @property
    def sess(self) -> int:
        return self.bridge.data.sess

    @sess.setter
    def sess(self, value: int) -> None:
        self.bridge.data.sess = value

    @property
    def sess_list(self) -> list[str]:
        return self.bridge.data.sess_list

    @sess_list.setter
    def sess_list(self, value: list[str]) -> None:
        self.bridge.data.sess_list = value

    @property
    def level(self) -> int:
        return self.bridge.data.level

    @level.setter
    def level(self, value: int) -> None:
        self.bridge.data.level = value

    # socket methods
    async def increase_score_unsafe(self, username: str, score: int) -> None:
        await self.bridge.send(username=username, session=score)

    async def increase_score(self, username: str, score: int) -> None:
        if self.username != ADMIN_USERNAME:
            raise PermissionDeniedError("Permission denied, maybe you should login as admin first")
        await self.increase_score_unsafe(username, score)

    async def get_user_info(self, username: str) -> None:
        await self.bridge.send(type=REQ.CTL_UINFO, msg=username)

    async def reload_info(self) -> None:
        await self.get_user_info(self.username)

    async def send_msg(self, msg: str | bytes) -> None:
        await self.bridge.send(msg=msg)

    async def send_relay_msg(self, visible: str | None, msg: str) -> None:
        await self.bridge.send_relay(visible=visible if visible else "", msg=msg)

    async def create_session(self, session_name: str) -> None:
        await self.bridge.send(type=REQ.CTL_NEWSE, username=session_name)

    async def join_session(self, session_id: int) -> None:
        await self.bridge.send(type=REQ.CTL_JOINS, session=session_id)

    async def quit_session(self, session_id: int) -> None:
        await self.bridge.send(type=REQ.CTL_QUITS, session=session_id)

    async def list_session(self, session_id: int) -> None:
        await self.bridge.send(type=REQ.CTL_SESS)